package com.xjk.ftp;

import com.xjk.date.DateUtil;
import com.xjk.string.BrandFileConstants;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;


/**
 * 文件工具
 *
 * <pre>
 * 功能列表
 *  1.将文件复制到新目录，可以给新文件名 copyFile(File file, String newFilePath, String newFileName)
 *  2.得到目录下所有文件，可以配置是否获取子目录文件getFileArray(String path, boolean isGetInner)
 *  3.得到目录下文件，包含目录也会返回<s>getFileArray(String path)</s>{@link #getFileArray(String, boolean)}
 *  4.拷贝文件到新目录，可指定缓存size,copyFile(InputStream is, String newFilePath, String newFileName, Integer buffer)
 *  5.移动文件到新目录，moveFile(String sourcePath, String sourceFile, String dscPath)
 *  6.移动文件到该目录的/.done/${yyyyMMdd}/下，暂只NIKE使用该方法moveFile(File sourceFile)
 *  7.创建文件（文件为空的文件），待后续文件写入，createFileAsFile(String filepath, String FileName)
 *  8.判断文件是否可操作状态，canRead(String fromPath, File file, String doneFileName, String readLock)
 * </pre>
 *
 */
public class FileUtil{

    public static String SEGM_NEWLINE = "\r\n";

    public static String SEGM_COLUMN = ";";

    public static String SEGM_HOLDER = "---";

    /**
     * 拷贝文件或目录 使用方法为
     *
     * <pre>
     *  option1:FileUtil.copyFile(file,newFilePath,newFileName)
     * option2:FileUtil.copyFile(file,newFilePath,null)
     * option3:FileUtil.copyFile(directory,newFilePath,newFileName)---->此处会输出警告，因为拷贝的是目录的话，新的文件名不起任何效果
     * option4:FileUtil.copyFile(directory,newFilePath,null)
     * </pre>
     *
     * @param file
     *            等拷贝文件---可为文件目录
     * @param newFilePath
     *            新文件路径
     * @param newFileName
     *            新文件名----如果为空，文件名同待拷贝的文件名
     * @return
     * @Description:
     */
    public static boolean copyFile(File file,String newFilePath,String newFileName){
        boolean result = true;
        if (file.isDirectory()){
            if (!StringUtils.isEmpty(newFileName)){
                System.out.println("### WARN!!! The file is directory ! So the newFileName is unavailable!!!");
            }
            File[] childFileArray = file.listFiles();
            for (File childFile : childFileArray){
                result = copyFile(childFile, newFilePath + "/" + file.getName(), null);
                if (false == result){
                    break;
                }
            }
            return result;
        }else{
            InputStream is = null;
            // 如果新文件名为空的话，将原始文件名赋值给新文件名，
            if (StringUtils.isEmpty(newFileName)){
                newFileName = file.getName();
            }
            try{
                // 写入字节流
                is = new FileInputStream(file);
                // 调用方法将字节流写进新文件中
                result = copyFile(is, newFilePath, newFileName, null);
            }catch (FileNotFoundException e1){
                e1.printStackTrace();
                result = false;
            }catch (IOException e){
                e.printStackTrace();
                result = false;
            }finally{
                if (null != is){
                    try{
                        is.close();
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
            }

            return result;
        }
    }

    /**
     * 得到目录下的所有文件
     *
     * @param path
     * @param isGetInner
     *            是否获取子目录中的文件
     */
    public static File[] getFileArray(String path,boolean isGetInner){
        File file = new File(path);// 当前路径
        File[] fileArray = null;// 用于获取当前目录中的文件（子目录的文件由list先装载）
        List<File> allFile = new ArrayList<File>();// 用于装载已经获取到的文件
        if (file.exists()){// 如果文件存在的话，不存在只会返回一个空的文件数组
            if (file.isDirectory()){// 文件必须为目录，如果不是目录，也只会有一个空的数组
                if (isGetInner){// 是否获取子目录文件参数判断
                    fileArray = file.listFiles();
                    if (null != fileArray){
                        for (File children : fileArray){
                            if (children.isDirectory()){
                                // 如果是目录，而且是获取子目录的参数，那么递归获取子目录中的文件
                                allFile.addAll(Arrays.asList(getFileArray(children.getPath(), true)));
                            }else{
                                allFile.add(children);
                            }
                        }
                    }
                }else{
                    // 不读取子文件目录（将非目录文件放进文件集合中）
                    fileArray = file.listFiles();
                    for (File children : fileArray){
                        if (children.isFile()){
                            allFile.add(children);
                        }
                    }
                }
            }
        }else{
            // 如果目录不存在创建目录
            file.mkdirs();
        }
        // 将文件集合转成数组返回
        File[] fileArray2 = new File[allFile.size()];
        return allFile.toArray(fileArray2);
    }

    /**
     * 得到目录下的所有文件<br/>
     * 建议方法{@link #getFileArray(String, boolean)}
     */
    public static File[] getFileArray(String path){
        File file = new File(path);
        File[] fileArray = null;
        if (file.exists()){
            if (file.isDirectory()){
                fileArray = file.listFiles();
            }
        }
        return fileArray;
    }

    /**
     * 前三个条件都不能为空，buffer为空的话有默认值
     *
     * @param is
     *            输入流
     * @param newFilePath
     *            新文件路径
     * @param newFileName
     *            新文件名
     * @param buffer
     *            缓存空间大小，如果为空给为4kb大小
     */
    public static boolean copyFile(InputStream is,String newFilePath,String newFileName,Integer buffer) throws IOException{
        boolean result = false;
        if (null == is || StringUtils.isEmpty(newFilePath) || StringUtils.isEmpty(newFileName)){
            throw new IOException("### the InputStream or new file's path or new file's name is null!!!!!!!! - -!see my eyes, if i know you, you will be dead!" + "\nInputStream:" + is + "\nnewFilePath:" + newFilePath + "\nnewFileName:" + newFileName);
        }

        if (null != buffer){
            if (buffer <= 0){
                throw new IOException("### The stream buffer's size not greater than 0,please theck this param!");
            }
        }else{
            // 为空的话默认1024
            buffer = 4 * 1024;
        }
        File newDirectary = new File(newFilePath);
        if (!newDirectary.exists()){
            newDirectary.mkdirs();
        }
        File newFile = new File(newFilePath + "/" + newFileName);
        OutputStream os = new FileOutputStream(newFile);

        byte[] size = new byte[buffer];
        int index = 0;
        while ((index = is.read(size)) > 0){
            os.write(size, 0, index);
        }
        // 关闭输入流和输出流
        if (null != is){
            is.close();
        }
        if (null != os){
            os.flush();
            os.close();
        }
        result = true;
        return result;
    }

    /**
     * 移动文件
     */
    public static boolean moveFile(String sourcePath,String sourceFile,String dscPath){

        dscPath = dscPath.endsWith("/") ? dscPath : dscPath + "/";
        sourcePath = sourcePath.endsWith("/") ? sourcePath : sourcePath + "/";
        // 文件原地址
        File oldFile = new File(sourcePath + sourceFile);
        // 创建目录
        try{
            dynamicCreateDir(dscPath);
        }catch (IOException e){
            e.printStackTrace();
        }
        // 文件新（目标）地址
        String newFile = dscPath + sourceFile;
        // new一个新文件夹
        File fnewpath = new File(dscPath);
        // 判断文件夹是否存在
        if (!fnewpath.exists()){
            fnewpath.mkdirs();
        }
        // 将文件移到新文件里
        File fnew = new File(newFile);
        // 如果新文件已经存在，先删除新文件,否则会无法rename
        if (fnew.exists()){
            fnew.delete();
        }
        return oldFile.renameTo(fnew);
    }

    /**
     * 移动文件
     */
    public static boolean moveFileBoolean(String sourcePath,String sourceFile,String dscPath){
        dscPath = dscPath.endsWith("/") ? dscPath : dscPath + "/";
        sourcePath = sourcePath.endsWith("/") ? sourcePath : sourcePath + "/";
        // 文件原地址
        File oldFile = new File(sourcePath + sourceFile);
        // 创建目录
        try{
            dynamicCreateDir(dscPath);
        }catch (IOException e){
            e.printStackTrace();
        }
        // 将文件移到新文件里
        File fnew = new File(dscPath + sourceFile);
        // 如果新文件存在，将其删除（避免补数据时，无法移动）
        if (fnew.exists()){
            fnew.delete();
        }
        // 移动文件
        return oldFile.renameTo(fnew);
    }

    /**
     * 文件移动
     */
    public static void moveFile(File sourceFile){
        // 文件原地址
        File oldFile = sourceFile;
        // 文件新（目标）地址
        String newPath = oldFile.getParent() + "/.done/" + DateUtil.day() + "/";
        // new一个新文件夹
        File fnewpath = new File(newPath);
        // 判断文件夹是否存在
        if (!fnewpath.exists()){
            fnewpath.mkdirs();
        }
        // 将文件移到新文件里
        File fnew = new File(newPath + oldFile.getName());
        if (fnew.exists()){
            fnew = new File(newPath + DateUtil.now("HHmmssSSS") + oldFile.getName());
        }

        oldFile.renameTo(fnew);
    }

    public static void moveFile(File sourceFile,boolean isSuccess){
        // 文件原地址
        File oldFile = sourceFile;
        // 文件新（目标）地址
        String newPath = null;
        if (isSuccess){
            newPath = oldFile.getParent() + "/.done/" + DateUtil.day() + "/";
        }else{
            newPath = oldFile.getParent() + "/error/" + DateUtil.day() + "/";
        }
        // new一个新文件夹
        File fnewpath = new File(newPath);
        // 判断文件夹是否存在
        if (!fnewpath.exists()){
            fnewpath.mkdirs();
        }
        // 将文件移到新文件里
        File fnew = new File(newPath + oldFile.getName());
        if (fnew.exists()){
            fnew = new File(newPath + DateUtil.now("HHmmssSSS") + oldFile.getName());
        }

        oldFile.renameTo(fnew);
    }

    /**
     * 获取文件的InputStream
     */
    public static InputStream getInputStream(String path){
        return Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
    }

    /**
     * 获取文件的OutputStream
     */
    public static OutputStream getFileOutputStream(String path,boolean isAppend) throws FileNotFoundException{
        try{
            // URL is = Thread.currentThread().getContextClassLoader().getResource(FileName);
            return new FileOutputStream(path, isAppend);
        }catch (FileNotFoundException e){
            throw e;
        }
    }

    /**
     * 创建文件
     */
    public static File createFileAsFile(String filepath,String fileName) throws Exception{
        File file = null;
        try{
            if (null != filepath && !"".equals(filepath.trim())){
                String ch = filepath.substring(filepath.length() - 1, filepath.length());
                if (!"/".equals(ch) && !"\\".equals(ch)){
                    filepath = filepath + "/";
                }
                if (!new File(filepath).isDirectory()){
                    file = new File(filepath);
                    file.mkdirs();
                }
            }
            if (null != fileName && !"".equals(fileName.trim())){
                file = new File(filepath + fileName);
                file.createNewFile();
            }
        }catch (Exception e){
            throw e;
        }
        return file;
    }

    /**
     * 根据目录和文件名生成文件
     */
    public static void createFile(String path,String fileName,String content,String charsetName) throws IOException{
        if (charsetName == null || "".equals(charsetName)){
            // 默认UTF-8
            charsetName = BrandFileConstants.CHARSET_UTF_8;
        }
        // 目录生成b *
        File directory = new File(path);
        if (!directory.exists()){
            directory.mkdirs();
        }

        // 文件生成 
        byte[] byteArray = content.getBytes(charsetName);
        byte[] bom = new byte[] {};
        if (BrandFileConstants.CHARSET_UTF_16LE.equalsIgnoreCase(charsetName)){
            bom = new byte[] { -1, -2 };
        }else if (BrandFileConstants.CHARSET_UTF_16BE.equalsIgnoreCase(charsetName)){
            bom = new byte[] { -2, -1 };
        }
        byte[] allByteArray = new byte[byteArray.length + bom.length];
        allByteArray = ArrayUtils.addAll(bom, byteArray);
        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(allByteArray), charsetName);
        File file = new File(path + "/" + fileName);

        FileOutputStream fos = new FileOutputStream(file);

        OutputStreamWriter bw = new OutputStreamWriter(fos, charsetName);

        final char[] buffer = new char[1024];
        int n = isr.read(buffer);
        while (-1 != n){
            bw.write(buffer, 0, n);
            n = isr.read(buffer);
        }
        bw.flush();
        fos.flush();
        bw.close();
        fos.close();
    }

    /**
     * 根据目录和文件名生成文件
     */
    public static void createUTF8BOMFile(String path,String fileName,String content,String charsetName) throws IOException{
        if (charsetName == null || "".equals(charsetName)){
            // 默认UTF-8
            charsetName = "UTF-8";
        }
        // 目录生成b *
        File directory = new File(path);
        if (!directory.exists()){
            directory.mkdirs();
        }

        // 文件生成 
        String bomCharsetName = charsetName;
        byte[] byteArray = null;
        if (charsetName.indexOf("UTF-8") > -1){
            byteArray = content.getBytes("UTF-8");
            charsetName = "UTF-8";
        }else{
            byteArray = content.getBytes(charsetName);
        }
        byte[] bom = new byte[] {};
        if ("UTF-16LE".equalsIgnoreCase(charsetName)){
            bom = new byte[] { -1, -2 };
        }else if ("UTF_16BE".equalsIgnoreCase(charsetName)){
            bom = new byte[] { -2, -1 };
        }
        byte[] allByteArray = new byte[byteArray.length + bom.length];
        allByteArray = ArrayUtils.addAll(bom, byteArray);
        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(allByteArray), charsetName);
        File file = new File(path + "/" + fileName);

        FileOutputStream fos = new FileOutputStream(file);
        if (bomCharsetName.indexOf("UTF-8-BOM") > -1){
            fos.write(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF });
        }
        OutputStreamWriter bw = new OutputStreamWriter(fos, charsetName);

        final char[] buffer = new char[1024];
        int n = isr.read(buffer);
        while (-1 != n){
            bw.write(buffer, 0, n);
            n = isr.read(buffer);
        }
        bw.flush();
        fos.flush();
        bw.close();
        fos.close();
    }

    /**
     * 根据目录和文件名生成文件
     */
    public static void createFile(String path,String fileName,String content) throws IOException{
        //目录生成b
        File directory = new File(path);
        if (!directory.exists()){
            directory.mkdirs();
        }

        // 文件生成 
        File file = new File(path + "/" + fileName);

        FileOutputStream fos = new FileOutputStream(file);
        byte[] byteArray = content.getBytes();
        ByteArrayInputStream in = new ByteArrayInputStream(byteArray);
        byte[] buffer = new byte[1024];
        int byteread = 0;
        while ((byteread = in.read(buffer)) != -1){
            // 文件写操作
            fos.write(buffer, 0, byteread);
        }
        fos.flush();
        fos.close();
    }

    /**
     * 创建文件
     *
     * @param filepath 文件路径
     * @param fileName 文件名
     */
    public static boolean createFile(String filepath,String fileName) throws Exception{
        try{
            if (null != filepath && !"".equals(filepath.trim())){
                String ch = filepath.substring(filepath.length() - 1, filepath.length());
                if (!"/".equals(ch) && !"\\".equals(ch)){
                    filepath = filepath + "/";
                }
            }
            if (!new File(filepath).isDirectory()){
                new File(filepath).mkdirs();
            }
            if (null != fileName && !"".equals(fileName.trim()) && !new File(filepath + fileName).isFile()){
                return new File(filepath + fileName).createNewFile();
            }
        }catch (Exception e){
            throw e;
        }
        return true;
    }

    /**
     * 将字符串写入文件
     *
     * @param path  文件名
     * @param source 写入的字符串
     * @param isAppend 是否追加
     * @throws ParseException
     */
    public static void writeFile(String path,String source,boolean isAppend) throws Exception{
        byte[] bytes = source.getBytes();
        OutputStream os = getFileOutputStream(path, isAppend);
        os.write(bytes);
        os.close();
    }

    /**
     * 将字符串写入文件
     *
     * @param path  文件名
     * @param source 写入的字符串
     * @throws ParseException
     */
    public static void writeFile(String path,String source) throws Exception{
        byte[] bytes = source.getBytes();
        OutputStream os = getFileOutputStream(path, false);
        os.write(bytes);
        os.close();
    }

    /**
     * 将输入流利用输出流写入文件
     *
     * @param filePath 文件路径
     * @param fileName 文件名
     * @param in 输入流
     * @throws ParseException
     */
    public static void writeFile(String filePath,String fileName,InputStream in) throws Exception{
        BufferedOutputStream outStream = null;
        BufferedInputStream inputStream = null;
        try{
            outStream = new BufferedOutputStream(new FileOutputStream(createFileAsFile(filePath, fileName)));
            inputStream = new BufferedInputStream(in);
            int c;
            while ((c = inputStream.read()) != -1){
                outStream.write(c);
                outStream.flush();
            }
        }catch (Exception exception){
            exception.printStackTrace();
            throw exception;
        }finally{
            if (outStream != null){
                outStream.close();
            }
            if (inputStream != null){
                inputStream.close();
            }
        }
    }

    /**
     * 读取文件
     *
     * @param path 文件名
     * @return String
     */
    public static String readFile(String path) throws Exception{
        String output = "";
        File file = new File(path);
        if (file.exists()){
            if (file.isFile()){
                BufferedReader input = new BufferedReader(new FileReader(file));
                StringBuffer buffer = new StringBuffer();
                String text = "";
                while ((text = input.readLine()) != null){
                    buffer.append(text).append("\n");
                }
                output = buffer.toString();
                if (input != null){
                    input.close();
                }
            }else if (file.isDirectory()){
                String[] dir = file.list();
                output += "Directory contents:\n";
                for (int i = 0; i < dir.length; i++){
                    output += dir[i] + "\n";
                }
            }
        }else{
            throw new Exception("file:" + path + " Does not exist!");
        }
        return output;
    }

    /**
     * 读取文件
     */
    public static String readFile(InputStream stream) throws Exception{
        byte b[] = new byte[1024];
        int len = 0;
        // 所有读取的内容都使用temp接收
        int temp = 0;
        // 当没有读取完时，继续读取
        while ((temp = stream.read()) != -1){
            b[len] = (byte) temp;
            len++;
        }
        stream.close();
        String result = new String(b, 0, len);
        return result;
    }

    /**
     * 删除文件
     *
     * @param 文件名
     * @return bollean
     * @throws ParseException
     */
    public static boolean deleteFile(String path){
        File file = new File(path);

        if (file.exists()){
            if (file.isFile()){
                return file.delete();
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

    /**
     * 遍历文件夹下所有匹配文件
     *
     * @param file
     *            File 起始文件夹
     * @param p
     *            Pattern 匹配类型
     * @return ArrayList 其文件夹下的文件夹
     */
    private static ArrayList<File> filePattern(File file,Pattern p){
        if (file == null){
            return null;
        }else if (file.isFile()){
            Matcher fMatcher = p.matcher(file.getName());
            if (fMatcher.matches()){
                ArrayList<File> list = new ArrayList<File>();
                list.add(file);
                return list;
            }
        }else if (file.isDirectory()){
            File[] files = file.listFiles();
            if (files != null && files.length > 0){
                ArrayList<File> list = new ArrayList<File>();
                for (int i = 0; i < files.length; i++){
                    ArrayList<File> rlist = filePattern(files[i], p);
                    if (rlist != null){
                        list.addAll(rlist);
                    }
                }
                return list;
            }
        }
        return null;
    }

    /**
     * 查找文件
     */
    public static File[] refreshFileList(String...para){
        String strPath = "";
        String s = "";
        if (para.length > 1){
            strPath = para[0];
            s = para[1];
        }else if (para.length == 1){
            strPath = para[0];
            s = "*";
        }else if (para.length == 0){
            return null;
        }

        File dir = new File(strPath);

        s = s.replace('.', '#');
        s = s.replaceAll("#", "\\\\.");
        s = s.replace('*', '#');
        s = s.replaceAll("#", ".*");
        s = s.replace('?', '#');
        s = s.replaceAll("#", ".?");
        s = "^" + s + "$";

        Pattern p = Pattern.compile(s);
        ArrayList<?> list = filePattern(dir, p);
        int filesize = 0;
        if (list != null){
            filesize = list.size();

            File[] files = new File[filesize];
            list.toArray(files);

            if (files == null || files.length == 0){
                return null;
            }
            return files;
        }else{
            return null;
        }
    }

    /**
     * 目录创建
     *
     * @param path
     * @return
     * @throws IOException
     * @Description:
     */
    public static File dynamicCreateDir(String path) throws IOException{
        File dir = new File(path);
        if (dir.exists()){
            if (dir.isDirectory()){
                return dir;
            }else{
                throw new IOException("File exists of that name");
            }
        }else{
            dir.mkdirs();
            return dir;
        }
    }

    /**
     *
     * @param fromPath，文件路径
     * @param file//
     *            文件
     * @param readLock
     * @Description:
     */
    public static boolean canRead(String fromPath,File file,String doneFileName,String readLock){
        boolean canRead = true;
        String fileName = file.getName();
        if (!fromPath.endsWith("/") && !fromPath.endsWith("\\")){
            fromPath += "/";
        }
        // 判断.done文件是否存在
        File doneFile = new File(fromPath + fileName + doneFileName);
        if (!doneFile.exists()){
            // .done文件不存在，那么将会被排除
            canRead = false;
        }
        if (null != readLock && !"".equals(readLock.trim())){
            if (!readLock.startsWith(".")){
                readLock = "." + readLock;
            }
            // 要进行锁配置判断
            File lockFile = new File(fromPath + fileName + readLock);
            if (lockFile.exists()){
                canRead = false;
            }
        }
        return canRead;
    }

    public static byte[] getByte(File file){
        byte[] ret = null;
        try{
            if (file == null){
                // log.error("helper:the file is null!");
                return null;
            }
            FileInputStream in = new FileInputStream(file);
            ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
            byte[] b = new byte[4096];
            int n;
            while ((n = in.read(b)) != -1){
                out.write(b, 0, n);
            }
            in.close();
            out.close();
            ret = out.toByteArray();
        }catch (IOException e){
            // log.error("helper:get bytes from file process error!");
            e.printStackTrace();
        }
        return ret;
    }
}
